%name json_

%include {
    global $CFG;
    require_once($CFG->dirroot . '/blocks/formal_langs/tokens_base.php');
 }

%include_class {
    public $error;
    public $ast;
    public $success = false;

    public $dump_info = '';
    
    private $debug_mode = false;
    private $node_num = 0;
    
    public function set_debug_mode($flag) {
        $this->debug_mode = $flag;
    }

    public function dump() {
        if ($this->debug_mode) {
            ob_start();
            $this->dump_info .= "<pre>Stack dump:\n";
            var_dump($this->yystack);
            $this->dump_info .= ob_get_contents();
            ob_end_clean();

            ob_start();
            $this->dump_info .= "$this->list dump:\n";
            var_dump($this->ast);
            $this->dump_info .= ob_get_contents();
            ob_end_clean();

            ob_start();
            $this->dump_info .= "$this->error dump:\n";
            var_dump($this->error);
            $this->dump_info .= ob_get_contents();
            ob_end_clean();
            $this->dump_indo .= "</pre>";
        }
    }

    public function process_token($token) {
        $this->doParse($token->type(), $token);
    }
}

%parse_failure {
    if ($this->debug_mode) {
        $this->dump_info .= "Parsing error.\n";
        $this->dump();
    }
    $this->success = false;
 }

%parse_accept {
    if ($this->debug_mode) {
        $this->dump_info .= "Parsing done.\n";
        $this->dump();
    }
    $this->success = true;
 }

%syntax_error {
    if ($this->debug_mode) {
        $this->dump_info .= "Syntax error.\n";
    }
 }

start ::= json(B) . {
    $this->ast = new block_formal_langs_ast(B);
}

json(A) ::= object(B) . {
    A = B;
}
json(A) ::= array(B) . {
    A = B;
}

object(A) ::= LBRACE(B) RBRACE(C) . {
    B->set_number($this->node_num++);
    C->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("object", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->add_child(C);
    $positions = array(B->position(), C->position());
    $result->set_position(block_formal_langs_node_position::summ($positions));
    A = $result;
}
object(A) ::= LBRACE(B) members(C) RBRACE(D) . {
    B->set_number($this->node_num++);
    D->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("object", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->add_child(C);
    $result->add_child(D);
    $positions = array(B->position(), C->position(), D->position());
    $result->set_position(block_formal_langs_node_position::summ($positions));
    A = $result;
}

members(A) ::= pair(B) . {
    $result = new block_formal_langs_ast_node_base("members", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->set_position(B->position());
    A = $result;
}
members(A) ::= members(B) COMMA(C) pair(D) . {
    C->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("members", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->add_child(C);
    $result->add_child(D);
    $positions = array(B->position(), C->position(), D->position());
    $result->set_position(block_formal_langs_node_position::summ($positions));
    A = $result;
}

pair(A) ::= STRING(B) COLON(C) value(D) . {
    B->set_number($this->node_num++);
    C->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("pair", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->add_child(C);
    $result->add_child(D);
    $positions = array(B->position(), C->position(), D->position());
    $result->set_position(block_formal_langs_node_position::summ($positions));
    A = $result;
}

array(A) ::= LSBRACE(B) RSBRACE(C) . {
    B->set_number($this->node_num++);
    C->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("array", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->add_child(C);
    $positions = array(B->position(), C->position());
    $result->set_position(block_formal_langs_node_position::summ($positions));
    A = $result;
}
array(A) ::= LSBRACE(B) elements(C) RSBRACE(D) . {
    B->set_number($this->node_num++);
    D->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("array", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->add_child(C);
    $result->add_child(D);
    $positions = array(B->position(), C->position(), D->position());
    $result->set_position(block_formal_langs_node_position::summ($positions));
    A = $result;
}

elements(A) ::= value(B) . {
    $result = new block_formal_langs_ast_node_base("elements", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->set_position(B->position());
    A = $result;
}
elements(A) ::= elements(B) COMMA(C) value(D) . {
    C->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("elements", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->add_child(C);
    $result->add_child(D);
    $positions = array(B->position(), C->position(), D->position());
    $result->set_position(block_formal_langs_node_position::summ($positions));
    A = $result;
}

value(A) ::= STRING(B) . {
    B->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("value", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->set_position(B->position());
    A = $result;
}
value(A) ::= INT(B) . {
    B->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("value", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->set_position(B->position());
    A = $result;
}
value(A) ::= DOUBLE(B) . {
    B->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("value", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->set_position(B->position());
    A = $result;
}
value(A) ::= BOOLEAN(B) . {
    B->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("value", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->set_position(B->position());
    A = $result;
}
value(A) ::= NULL(B) . {
    B->set_number($this->node_num++);
    $result = new block_formal_langs_ast_node_base("value", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->set_position(B->position());
    A = $result;
}
value(A) ::= object(B) . {
    $result = new block_formal_langs_ast_node_base("value", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->set_position(B->position());
    A = $result;
}
value(A) ::= array(B) . {
    $result = new block_formal_langs_ast_node_base("value", NULL, $this->node_num++, false);
    $result->add_child(B);
    $result->set_position(B->position());
    A = $result;
}
